package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.controller.CourseAuditController;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;


/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {


    @Autowired
    private CourseMarketService courseMarketService;

    /*
     * 步骤分析：
     *  1.是否需要开启事务
     *  2.判断关键数据
     *       分页数据
     *       查询条件
     *  3.构建mp分页对象
     *  4.构建查询条件对象LambdaQueryWrapper
     *  5.查询数据
     *  6.获得数据并封装返回结果
     *       封装PageVo数据
     * */
    @Override
    public PageVO<CourseBaseDTO> queryCourseList(PageRequestParams params, QueryCourseModel model,Long companyId) {

        if (params.getPageNo()<1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }

        if (params.getPageSize()<1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

/*        if (StringUtil.isNotBlank(model.getAuditStatus())) {
            // 添加的审核状态条件（eq）
            queryWrapper.eq(CourseBase::getAuditStatus, model.getAuditStatus());
        }

        if (StringUtil.isNotBlank(model.getCourseName())) {
            queryWrapper.like(CourseBase::getName, model.getCourseName());
        }*/
        if (!(ObjectUtils.nullSafeEquals(companyId,
                CourseAuditController.OPERATION_FLAG))) {
            queryWrapper.eq(CourseBase::getCompanyId, companyId);
        }

        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()), CourseBase::getAuditStatus, model.getAuditStatus());
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()), CourseBase::getName, model.getCourseName());

        Page<CourseBase> page = new Page<>(params.getPageNo(),params.getPageSize());
        Page<CourseBase> pageResult = this.page(page, queryWrapper);

        List<CourseBase> records = pageResult.getRecords();
        long total = pageResult.getTotal();

        // 5.将 po 数据转换为
        List<CourseBaseDTO> dtos = Collections.emptyList();
        if (!(CollectionUtils.isEmpty(records))) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }

        // 4.将查询结果封装到PageVO中
        /*
         * PageVO构造方法：
         *   1.当前页的集合数据
         *   2.数据库中的总条数
         *   3.当前页码
         *   4.每页条数
         * */
        // 6.封装PageVO数据
        PageVO pageVO = new PageVO(dtos,total,params.getPageNo(),params.getPageSize());

        return pageVO;

    }

    /**
     * 添加录播课程
     * 步骤分析：
     * 1.是否要开启事务
     *    如果是增删改操作，必须要开启事务
     * 2.判断关键数据
     *   有此数据才可以进行操作，一般有前端来传入
     *     来源：
     *         数据库表约束
     *         前端页面的表单说明
     *             为必填项：红星
     *         api接口文档（Yapi）
     * 3.判断业务数据（添加没有业务数据判断）
     *   系统中存在的数据，如果数据状态有问题，当前操作要终止，一般数据来源于后端
     * 4.判断数据是否要被赋值（默认值）
     *     status：数据库已经赋值，无需操作
     *     审核状态 auditStatus：新添加的课程默认审核状态--未提交（状态码）
     * 5.将dto转为po数据
     *     因为mp的api只能对po数据进行操作
     * 6.保存数据并返回结果，判断结果是否成功
     * 7.如果操作成功，将数据转为dto并返回
     * @param
     * @return
     */
    //增删改需要开启事务
    @Transactional
    @Override
    public CourseBaseDTO creatCourseBase(CourseBaseDTO courseBaseDTO) {

        //关键数据的处理
        verifyCourseMsg(courseBaseDTO);

        //3.判断业务数据（添加没有业务数据判断）
        //   系统中存在的数据，如果数据状态有问题，当前操作要终止，一般数据来源于后端

        //4.判断数据是否要被赋值（默认值）
        //     status：数据库已经赋值，无需操作

        //     审核状态 auditStatus：新添加的课程默认审核状态--未提交（状态码）
        if (StringUtil.isBlank(courseBaseDTO.getAuditStatus())) {
            courseBaseDTO.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());
        }

        //5.将dto转为po数据
        //     因为mp的api只能对po数据进行操作
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2po(courseBaseDTO);


        //6.保存数据并返回结果，判断结果是否成功



        boolean courseBaseResult = this.save(courseBase);
        //7.如果操作成功，将数据转为dto并返回
        if (!courseBaseResult) {
            throw new RuntimeException("课程基础信息保存失败");
        }


        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(courseBaseDTO.getCharge());
        String charge = courseBaseDTO.getCharge();

        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            BigDecimal price = courseBaseDTO.getPrice();

            if (ObjectUtils.isEmpty(price)) {
                throw new RuntimeException("收费课程价格不能为空");
            }
            courseMarket.setPrice(courseBaseDTO.getPrice().floatValue());
        }

        boolean marketResult = courseMarketService.save(courseMarket);
        if (!marketResult) {
            throw new RuntimeException("课程营销信息保存失败");
        }

        // 7.如果操作成功，将数据转为dto并返回
        // 将数据库中的最新数据转为dto
        Long id = courseBase.getId();
        CourseBaseDTO resultDTO = getLastCourseBaseDTO(courseBaseDTO, id);

        return resultDTO;
    }

    private void verifyCourseMsg(CourseBaseDTO dto) {
        if (org.springframework.util.ObjectUtils.isEmpty(dto.getCompanyId())) {
            // 业务异常：程序员在做业务判断时，数据有问题。
            // 异常：
            //    1.终止程序
            //    2.传递错误信息
            //    3.使用运行时异常来抛出
            //        运行时异常不需在编译期间处理
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }

        if (StringUtil.isBlank(dto.getName())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }

        if (StringUtil.isBlank(dto.getMt())) {
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }

        if (StringUtil.isBlank(dto.getSt())) {
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }

        if (StringUtil.isBlank(dto.getGrade())) {
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }

        if (StringUtil.isBlank(dto.getTeachmode())) {
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }

        if (StringUtil.isBlank(dto.getUsers())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }

        if (StringUtil.isBlank(dto.getCharge())) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }
    }

    private CourseBaseDTO getLastCourseBaseDTO(CourseBaseDTO dto, Long id) {
        CourseBase po = this.getById(id);

        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());
        return resultDTO;
    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *       courseBaseId  companyId
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *       课程营销
     *   3.查询数据并转为dto返回
     *
     * */
    @Override
    public CourseBaseDTO getCourseBaseById(Long courseBaseId, Long companyId) {

        //1.判断关键数据
        //     courseBaseId  companyId
        if (org.springframework.util.ObjectUtils.isEmpty(courseBaseId)||
                org.springframework.util.ObjectUtils.isEmpty(companyId)
        ) {
            throw new RuntimeException("传入参数和接口不匹配");
        }


        // 2.判断业务数据
        //     课程基础信息
        //         判断是否存在
        //         判断是否是同一家教学机构
        //         判断是否删除
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);


        //     课程营销
        CourseMarket courseMarket = getCourseMarketByCourseId(courseBaseId);


        // 3.查询数据并转为dto返回
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        courseBaseDTO.setCharge(courseMarket.getCharge());
        courseBaseDTO.setPrice(new BigDecimal(courseMarket.getPrice().toString()));


        return courseBaseDTO;
    }

    private CourseMarket getCourseMarketByCourseId(Long courseBaseId) {
        LambdaQueryWrapper<CourseMarket> marketQueryWrapper = new LambdaQueryWrapper<>();
        marketQueryWrapper.eq(CourseMarket::getCourseId, courseBaseId);

        CourseMarket courseMarket = courseMarketService.getOne(marketQueryWrapper);

        if (org.springframework.util.ObjectUtils.isEmpty(courseMarket)) {
            throw new RuntimeException("课程营销数据不存在");
        }
        return courseMarket;
    }

    private CourseBase getCourseBaseByBaseId(Long courseBaseId, Long companyId) {
        LambdaQueryWrapper<CourseBase> baseQueryWrapper = new LambdaQueryWrapper<>();
        baseQueryWrapper.eq(CourseBase::getId, courseBaseId);
        baseQueryWrapper.eq(CourseBase::getCompanyId, companyId);

        CourseBase courseBase = this.getOne(baseQueryWrapper);

        if (org.springframework.util.ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("课程不存在");
        }

        Integer status = courseBase.getStatus();
        if (!(CommonEnum.USING_FLAG.getCodeInt().equals(status))) {
            throw new RuntimeException("课程信息已经被删除");
        }
        return courseBase;
    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *       可以使用添加的判断
     *       修改时：课程id是必须存在
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *           判断课程审核状态：未提交、审核未通过
     *       课程营销
     *   3.修改数据内容
     *       课程基础信息表
     *           有些内容是不容修改的：courseBaseId、companyid、auditstatus、status
     *       课程营销数据表
     *           charge price
     *        修改数据时要判断修改后结果
     *
     *   4.返回前端最新的数据库的数据并封装为dto返回
     *
     * */
    @Override
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {

        //1.判断关键数据
        //     可以使用添加的判断
        //     修改时：课程id是必须存在
        verifyCourseMsg(dto);

        Long courseBaseId = dto.getCourseBaseId();
        if (org.springframework.util.ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("修改课程id不能为空");
        }

        // 2.判断业务数据
        //     课程基础信息
        //         判断是否存在
        //         判断是否是同一家教学机构
        //         判断是否删除
        //         判断课程审核状态：
        Long companyId = dto.getCompanyId();
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);


        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }

        //     课程营销
        CourseMarket courseMarket = getCourseMarketByCourseId(courseBaseId);


        // 3.修改数据内容
        //     课程基础信息表
        //         有些内容是不容修改的：companyid、auditstatus、status

        CourseBase po = CourseBaseConvert.INSTANCE.dto2po(dto);

        // 为了防止前端乱意修改内容
        po.setCompanyId(null);
        po.setAuditStatus(null);
        po.setStatus(null);

        boolean baseResult = this.updateById(po);

        if (!baseResult) {
            throw new RuntimeException("课程信息修改失败");
        }


        LambdaUpdateWrapper<CourseMarket> marketUpdateWrapper = new LambdaUpdateWrapper<>();
        marketUpdateWrapper.set(CourseMarket::getCharge,dto.getCharge());

        String charge = dto.getCharge();
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {

            BigDecimal price = dto.getPrice();
            if (org.springframework.util.ObjectUtils.isEmpty(price)) {
                throw new RuntimeException("收费课程价格不能为空");
            }

            marketUpdateWrapper.set(CourseMarket::getPrice,dto.getPrice().floatValue());
        }
        marketUpdateWrapper.eq(CourseMarket::getCourseId, courseBaseId);


        boolean marketResult = courseMarketService.update(marketUpdateWrapper);

        if (!marketResult) {
            throw new RuntimeException("修改课程营销数据失败");
        }

        //      修改数据时要判断修改后结果

        // 4.返回前端最新的数据库的数据并封装为dto返回
        CourseBaseDTO resultDTO = getLastCourseBaseDTO(dto, courseBaseId);

        return resultDTO;
    }

    @Override
    @Transactional
    public void removeCourseBase(Long courseBaseId, Long companyId) {

        //1.判断关键数据的合法性
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //2.根据Id获得课程基础信息并进行相应的判断
        //2.1 获得课程基础信息
        CourseBase courseBase = getById(courseBaseId);

        verifyPO(companyId, courseBase);


        //2.4 判断课程的审核状态
        String auditStatus = courseBase.getAuditStatus();

        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        // 3.修改课程信息状态值
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getStatus,CommonEnum.DELETE_FLAG.getCodeInt());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());

        updateWrapper.eq(CourseBase::getId, courseBase.getId());

        boolean result = update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }

    /**
     * 提交审核
     *
     * 业务分析
     *      1.判断关键数据
     *      2.判断业务数据
     *          课程基础信息
     *              判断是否存在
     *              判断是否是同一家教学机构
     *              判断是否删除
     *              判断审核状态
     *      3.修改课程审核状态
     *          已提交
     * @param courseBaseId
     * @param companyId
     */
    @Override
    @Transactional
    public void commitCourseBase(Long courseBaseId, Long companyId) {
//        1.判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId)||
            ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //2.判断业务数据
        //    课程基础信息
        //        判断是否存在
        //        判断是否是同一家教学机构
        //        判断是否删除
        //        判断审核状态
        getCourseByLogic(companyId, courseBaseId);


//        3.修改课程审核状态
//                已提交
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBaseId);

        boolean result = this.update(updateWrapper);

        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

    }

    /**
     * 课程审核(提交的课程才可审核)
     *  业务分析：
     *   1.判断关键数据
     *       auditMind  auditStatus  courseid
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否删除
     *           判断审核状态
     *               必须为：已提交
     *       审核状态
     *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
     *   3.修改课程审核信息
     *       auditMind  auditStatus  auditNum（每次+1）
     * @param dto
     */
    @Override
    @Transactional
    public void approve(CourseBaseDTO dto) {
        // 1.判断关键数据
        //      auditMind  auditStatus  courseid
        if (StringUtil.isBlank(dto.getAuditMind())||
                StringUtil.isBlank(dto.getAuditStatus())||
                ObjectUtils.isEmpty(dto.getCourseBaseId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //  2.判断业务数据
        //      课程基础信息
        //          判断是否存在
        //          判断是否删除
        //          判断审核状态
        //              必须为：已提交
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getId, dto.getCourseBaseId());
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());
        queryWrapper.eq(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());

        int count = this.count(queryWrapper);

        if (count < 1) {
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }

        //审核状态
        //运营平台只能给课程审核状态赋值：审核通过、审核未通过
        String auditStatus = dto.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120016);
        }



        //  3.修改课程审核信息
        //      auditMind  auditStatus  auditNum（每次+1）
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, dto.getAuditStatus());
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());
        // 使用redis来实现
        // updateWrapper.set(CourseBase::getAuditNums, dto.getAuditMind());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, dto.getCourseBaseId());

        boolean result = this.update(updateWrapper);

        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

    }

    /**
     * 课程基础信息
     *     判断是否存在
     *     判断是否是同一家教学机构
     *     判断是否删除
     *     判断审核状态
     * @param companyId
     * @param courseBaseId
     */
    private void getCourseByLogic(Long companyId, Long courseBaseId) {
        CourseBase courseBase = getCourseBaseByBaseId(companyId, courseBaseId);
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }


    }

    private void verifyPO(Long companyId, CourseBase courseBase) {
        // 判断课程数据是否存在
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }


        // 判断是否是同一家机构
        if (!(ObjectUtils.nullSafeEquals(companyId, courseBase.getCompanyId()))) {
            ExceptionCast.cast(CommonErrorCode.E_100108);
        }
    }

}
